package umage.figures;

import java.awt.Color;
import java.awt.Graphics2D;
import java.awt.event.ActionEvent;
import java.awt.geom.Point2D;
import java.awt.geom.Rectangle2D;
import java.awt.geom.Point2D.Double;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Collection;
import java.util.LinkedList;

import javax.swing.AbstractAction;
import javax.swing.Action;
import javax.swing.JOptionPane;

import org.jhotdraw.draw.Drawing;
import org.jhotdraw.draw.Figure;
import org.jhotdraw.draw.Handle;
import org.jhotdraw.draw.MoveHandle;
import org.jhotdraw.draw.RectangleFigure;
import org.jhotdraw.xml.DOMInput;
import org.jhotdraw.xml.DOMOutput;

@FigureInfo(icon = "TransitionFigure.png", name = "Transition Figure")
public class TransitionFigure extends RectangleFigure {
	
	protected boolean rotated;
	protected boolean lastFired;
	
	public TransitionFigure() {
		rotated = false;
		lastFired = false;
	}
	
	@Override
	public Collection<Action> getActions(Double p) {
		ArrayList<Action> actions = new ArrayList<Action>();
		actions.add(new FireAction());
		actions.add(new RotateAction());
		return actions;
	}
	
	@Override
	public Collection<Handle> createHandles(int detailLevel) {
		LinkedList<Handle> handles = new LinkedList<Handle>();
        if (detailLevel == 0) {
        	MoveHandle.addMoveHandles(this, handles);
        }
        return handles;
	}
	
	@Override
	public void basicSetBounds(Double anchor, Double lead) {
		Point2D.Double a = new Point2D.Double(Math.min(anchor.x, lead.x), Math.min(anchor.y, lead.y));
		Point2D.Double b;
		if (rotated) {
			b = new Point2D.Double(a.x + 20, a.y + 75);
		} else {
			b = new Point2D.Double(a.x + 75, a.y + 20);
		}
		super.basicSetBounds(a, b);
	}
	
	// Overridden since attribute seems to be ignored here despite multiple searches for the cause
	@Override
	protected void drawFill(Graphics2D g) {
		if (lastFired) g.setColor(Color.RED);
		else g.setColor(Color.BLACK);
		super.drawFill(g);
	}
	
	@Override
	public void read(DOMInput in) throws IOException {
		rotated = in.getAttribute("rotated", false);
		super.read(in);
	}
	
	@Override
	public void write(DOMOutput out) throws IOException {
		out.addAttribute("rotated", rotated);
		super.write(out);
	}
	
	@Override
	public TransitionFigure clone() {
		TransitionFigure that = (TransitionFigure) super.clone();
		that.rotated = rotated;
		return that;
	}
	
	protected class RotateAction extends AbstractAction {
		
		public RotateAction() {
			super("Rotate");
		}
		
		@Override
		public void actionPerformed(ActionEvent arg0) {
			rotated = !rotated;
			
			// Force the shape to update
			Rectangle2D.Double oldBounds = getBounds();
			oldBounds.height = 0;
			oldBounds.width = 0;
			setBounds(oldBounds);
		}
		
	}
	
	protected class FireAction extends AbstractAction {
		
		public FireAction() {
			super("Fire");
		}

		@Override
		public void actionPerformed(ActionEvent e) {
			if (!fire()) {
				JOptionPane.showMessageDialog(null, "Transition Failed to Fire\nRequirements not met", "Transition Failure", JOptionPane.WARNING_MESSAGE);
			}
		}
		
	}
	
	public boolean canFire() {
		boolean connected = false;
		for (Figure figure : getDrawing().getFigures()) {
			if (figure instanceof FlowArrow) {
				FlowArrow arrow = (FlowArrow) figure;
				if (arrow.getStartFigure() == this) {
					if (!(arrow.getEndFigure() instanceof PlaceFigure)) continue;
					PlaceFigure place = (PlaceFigure) arrow.getEndFigure();
					if (!place.canAddTokens(arrow.getTransferCount())) return false;
					connected = true;
					
				} else if (arrow.getEndFigure() == this) {
					if (!(arrow.getStartFigure() instanceof PlaceFigure)) continue;
					PlaceFigure place = (PlaceFigure) arrow.getStartFigure();
					if (!place.canRemoveTokens(arrow.getTransferCount())) return false;
					connected = true;
				}
			}
		}
		return connected;
	}
	
	public boolean fire() {
		if (!canFire()) return false;
		clearAllFire(getDrawing());
		
		for (Figure figure : getDrawing().getFigures()) {
			if (figure instanceof FlowArrow) {
				FlowArrow arrow = (FlowArrow) figure;
				if (arrow.getStartFigure() == this) {
					if (!(arrow.getEndFigure() instanceof PlaceFigure)) continue;
					PlaceFigure place = (PlaceFigure) arrow.getEndFigure();
					place.addTokens(arrow.getTransferCount());
					
				} else if (arrow.getEndFigure() == this) {
					if (!(arrow.getStartFigure() instanceof PlaceFigure)) continue;
					PlaceFigure place = (PlaceFigure) arrow.getStartFigure();
					place.removeTokens(arrow.getTransferCount());
					
				}
			}
		}
		
		lastFired = true;
		return true;
	}
	
	public void clearFire() {
		lastFired = false;
	}
	
	public static void clearAllFire(Drawing d) {
		for (Figure figure : d.getFigures()) {
			if (figure instanceof TransitionFigure) {
				((TransitionFigure)figure).clearFire();
			}
		}
	}
	
}
